package rtree;

import java.util.ArrayList;
import java.util.List;

import spatialindex.IData;
import spatialindex.IEntry;
import spatialindex.INode;
import spatialindex.IQueryStrategy;
import spatialindex.ISpatialIndex;
import spatialindex.IVisitor;
import spatialindex.Point;
import spatialindex.Region;

public class RTreeUtil {

	/**
	 * RTreeQuery; intersection and knn
	 * 
	 * @param RTree
	 * @param queryType
	 * @param point1
	 * @param point2
	 * @return
	 */
	public List<Integer> RTreeQuery(ISpatialIndex RTree, String queryType,
			double[] point1, double[] point2) {
		List<Integer> resultIds = new ArrayList<Integer>();
		try {
			MyQueryStrategy qs = new MyQueryStrategy();
			RTree.queryStrategy(qs);

			MyVisitor vis = new MyVisitor(resultIds);

			if (queryType.equals("intersection")) {
				if (point2 != null) {
					Region r = new Region(point1, point2);
					RTree.intersectionQuery(r, vis);
				} else {
					Point p = new Point(point1);
					RTree.intersectionQuery(p, vis);
				}
				// this will find all data that intersect with the query
				// range.
			} else if (queryType.contains("NN")) {
				int k = Integer.parseInt(queryType.substring(0, 1));
				Point p = new Point(point1);
				RTree.nearestNeighborQuery(k, p, vis);
			} else {
				System.err.println("Unknown query type.");
				System.exit(-1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return resultIds;
	}
	
	
	// example of a Visitor pattern.
		// see RTreeQuery for a more elaborate example.
		class MyVisitor implements IVisitor {
			public int m_indexIO = 0;
			public int m_leafIO = 0;
			private List<Integer> resultIds;

			public MyVisitor(List<Integer> resultIds) {
				this.resultIds = resultIds;
			}

			public void visitNode(final INode n) {
				if (n.isLeaf())
					m_leafIO++;
				else
					m_indexIO++;
			}

			public void visitData(final IData d) {
				// System.out.print(d.getIdentifier() + ", ");
				// System.out.println();
				this.resultIds.add(d.getIdentifier());

				// the ID of this data entry is an answer to the query. I will just
				// print it to stdout.
			}

		}

		// example of a Strategy pattern.
		// traverses the tree by level.
		class MyQueryStrategy implements IQueryStrategy {
			private ArrayList ids = new ArrayList();

			public void getNextEntry(IEntry entry, int[] nextEntry,
					boolean[] hasNext) {
				Region r = entry.getShape().getMBR();

				// System.out.println(r.m_pLow[0] + " " + r.m_pLow[1]);
				// System.out.println(r.m_pHigh[0] + " " + r.m_pLow[1]);
				// System.out.println(r.m_pHigh[0] + " " + r.m_pHigh[1]);
				// System.out.println(r.m_pLow[0] + " " + r.m_pHigh[1]);
				// System.out.println(r.m_pLow[0] + " " + r.m_pLow[1]);
				// System.out.println();
				// System.out.println();
				// print node MBRs gnuplot style!

				// traverse only index nodes at levels 2 and higher.
				if (entry instanceof INode && ((INode) entry).getLevel() > 1) {
					for (int cChild = 0; cChild < ((INode) entry)
							.getChildrenCount(); cChild++) {
						ids.add(new Integer(((INode) entry)
								.getChildIdentifier(cChild)));
					}
				}

				if (!ids.isEmpty()) {
					nextEntry[0] = ((Integer) ids.remove(0)).intValue();
					hasNext[0] = true;
				} else {
					hasNext[0] = false;
				}
			}
		};
	
}
